/* global TextDecoder */
'use strict'
class Compile {
  escape (str) {
    return str.toString()
      .replace(/@/g, '@A')
      .replace(/\//g, '@S')
  }
  unescape (str) {
    return str.replace(/@A/g, '@')
      .replace(/@S/g, '/')
  }
  serialize (obj) {
    if (!obj) {
      return
    }
    var kvPairs = []
    for (var key in obj) {
      if (obj.hasOwnProperty(key)) {
        kvPairs.push(this.escape(key)
          .concat('@=')
          .concat(this.escape(obj[key])))
      }
    }
    return kvPairs.join('/').concat('/').concat('\0')
  }
  deserialize (objStr) {
    if (!objStr) {
      return
    }
    var obj = {}
    var kvPairs = objStr.split('/')
    kvPairs.forEach(function (kvStr) {
      var kv = kvStr.split('@=')
      if (kv.length !== 2) {
        return
      }
      var key = this.unescape(kv[0])
      var value = this.unescape(kv[1])
      if (value.indexOf('@=') >= 0) {
        value = this.deserialize(value)
      }
      obj[key] = value
    }.bind(this))
    return obj
  }
  toBuffer (obj) {
    var str = this.serialize(obj)
    var buf = new ArrayBuffer(str.length * 2 + 12)
    var dataview = new DataView(buf)
    for (var i = 0, strLen = str.length; i < strLen; i++) {
      dataview.setUint16(12 + i, str.charCodeAt(i), true)
    }
    dataview.setUint32(0, buf.byteLength - 4, true)
    dataview.setUint32(4, buf.byteLength - 4, true)
    dataview.setUint16(8, 689, true)
    dataview.setUint16(10, 0, true)
    return buf
  }

  toJson (data) {
    try {
      if (data) {
        var dataView = new DataView(data, 12)
        var decoder = new TextDecoder('utf8')
        var decodedString = decoder.decode(dataView)
        return this.deserialize(decodedString)
      }
    } catch (e) {
      return null
    } finally {}
  }
}

export var compile = new Compile()
